﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.IO.Ports;

using System.Threading;

namespace NewDevice.XiWei
{
    /// <summary>
    /// 串口协议处理器 - 支持异步接收、缓存管理和帧解析
    /// </summary>
    public class SerialProtocolHandler : IDisposable
    {
        #region 常量和字段

        // 有效的帧头命令列表（根据用户协议定义）
        private static readonly HashSet<byte> ValidHeaders = new HashSet<byte>
        {
            0xBB, 0xDD, 0xFF, 0x11, 0x22, 0x33, 0x55, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB8, 0xB9,
            0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0x61, 0x62,0x3F,0x41,0x42
        };

        private readonly SerialPort _serialPort;
        private readonly List<byte> _receiveBuffer = new List<byte>();
        private readonly object _bufferLock = new object();
        private readonly CancellationTokenSource _cts;
        private Task _parseTask;
        private Task _readTask;
        private DateTime _lastReceivedTime = DateTime.Now;
        private const int FrameTimeoutMs = 200; // 帧超时时间(毫秒)

        #endregion 常量和字段

        #region 事件定义

        /// <summary>
        /// 当完整帧被解析时触发
        /// </summary>
        public event Action<byte[]> OnFrameReceived;

        /// <summary>
        /// 当发生错误时触发
        /// </summary>
        public event Action<string> OnError;

        /// <summary>
        /// 当有日志信息时触发
        /// </summary>
        public event Action<string> OnLog;

        #endregion 事件定义

        #region 构造函数和初始化

        /// <summary>
        /// 初始化串口协议处理器
        /// </summary>
        /// <param name="portName">串口名称</param>
        /// <param name="baudRate">波特率</param>
        public SerialProtocolHandler(string portName, int baudRate = 115200)
        {
            _serialPort = new SerialPort(portName, baudRate)
            {
                DtrEnable = true,
                ReceivedBytesThreshold = 1,
                ReadTimeout = 100,
                WriteTimeout = 100,
                DataBits = 8,
                StopBits = StopBits.One,
                Parity = Parity.None,
            };

            _cts = new CancellationTokenSource();
        }

        /// <summary>
        /// 打开串口并启动解析线程
        /// </summary>
        public void Open()
        {
            try
            {
                _serialPort.Open();
                _serialPort.DataReceived += DataReceivedHandler;

                // 启动解析线程
                _parseTask = Task.Run(ParseData, _cts.Token);
                //_readTask = Task.Run(ReadData, _cts.Token);
                OnLog?.Invoke($"串口 {_serialPort.PortName} 已打开，波特率: {_serialPort.BaudRate}");
            }
            catch (Exception ex)
            {
                OnError?.Invoke($"打开串口失败: {ex.Message}");
                throw;
            }
        }

        #endregion 构造函数和初始化

        #region 数据接收处理

        /// <summary>
        /// 串口数据接收事件处理
        /// </summary>
        private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                int bytesToRead = _serialPort.BytesToRead;
                if (bytesToRead == 0) return;

                byte[] buffer = new byte[bytesToRead];

                _serialPort.Read(buffer, 0, bytesToRead);

                lock (_bufferLock)
                {
                    _receiveBuffer.AddRange(buffer);
                    _lastReceivedTime = DateTime.Now;
                }

                OnLog?.Invoke($"收到 {bytesToRead} 字节数据 {ByteToString(buffer)}");
            }
            catch (Exception ex)
            {
                OnError?.Invoke($"数据接收错误: {ex.Message}");
            }
        }

        #endregion 数据接收处理

        #region 数据解析逻辑

        /// <summary>
        /// 解析线程主循环
        /// </summary>
        private void ParseData()
        {
            while (!_cts.IsCancellationRequested)
            {
                try
                {
                    // 处理接收缓冲区
                    ProcessBuffer();

                    // 降低CPU占用
                    //Thread.Sleep(2);
                }
                catch (Exception ex)
                {
                    OnError?.Invoke($"解析线程错误: {ex.Message}");
                }
            }
        }

        /// <summary>
        /// 解析线程主循环
        /// </summary>
        private async void ReadData()
        {
            byte[] buffer = new byte[1024]; // 设置一个合理的读取缓冲区
            while (!_cts.IsCancellationRequested)
            {
                try
                {
                    // 使用BaseStream进行异步读取，不阻塞线程
                    int bytesRead = await _serialPort.BaseStream.ReadAsync(buffer, 0, buffer.Length, _cts.Token);
                    if (bytesRead > 0)
                    {
                        byte[] returnBuffer = new byte[bytesRead];

                        Array.Copy(buffer, returnBuffer, bytesRead);

                        lock (_bufferLock)
                        {
                            _receiveBuffer.AddRange(returnBuffer);
                            _lastReceivedTime = DateTime.Now;
                        }

                        OnLog?.Invoke($"收到 {bytesRead} 字节数据 {ByteToString(returnBuffer)}");
                    }
                }
                catch (Exception ex)
                {
                    OnError?.Invoke($"解析线程错误: {ex.Message}");
                }
            }
        }

        private void ProcessReceivedData(byte[] buffer, int bytesRead)
        {
            throw new NotImplementedException();
        }

        private string ByteToString(byte[] bytes)
        {
            return BitConverter.ToString(bytes).Replace("-", " ");
        }

        private string ByteToString(List<byte> bytes)
        {
            return BitConverter.ToString(bytes.ToArray()).Replace("-", " ");
        }

        /// <summary>
        /// 处理缓冲区中的数据
        /// </summary>
        private void ProcessBuffer()
        {
            lock (_bufferLock)
            {
                // 检查超时：如果长时间没有新数据，清空缓冲区
                if (_receiveBuffer.Count > 0 && (DateTime.Now - _lastReceivedTime).TotalMilliseconds > FrameTimeoutMs)
                {
                    OnError?.Invoke($"接收超时，清空 {_receiveBuffer.Count} 字节未处理数据[{ByteToString(_receiveBuffer)}]");
                    _receiveBuffer.Clear();
                    return;
                }

                // 尝试解析帧
                while (_receiveBuffer.Count >= 2) // 至少需要帧头和长度字节
                {
                    // 查找有效帧头
                    if (!ValidHeaders.Contains(_receiveBuffer[0]))
                    {
                        // 无效帧头，丢弃第一个字节
                        _receiveBuffer.RemoveAt(0);
                        continue;
                    }

                    byte frameHeader = _receiveBuffer[0];
                    byte frameLength = _receiveBuffer[1];

                    // 验证长度字段有效性
                    if (frameLength < 6 || frameLength > 64)
                    {
                        OnError?.Invoke($"无效长度字段: {frameLength}，丢弃帧头");
                        _receiveBuffer.RemoveAt(0);
                        continue;
                    }

                    // 检查是否收到完整帧
                    if (_receiveBuffer.Count < frameLength)
                    {
                        // 数据不完整，等待更多数据
                        break;
                    }

                    // 提取候选帧
                    byte[] candidateFrame = _receiveBuffer.Take(frameLength).ToArray();

                    // 验证CRC
                    if (ValidateModbusCrc(candidateFrame))
                    {
                        // 帧有效，触发事件
                        OnFrameReceived?.Invoke(candidateFrame);
                        OnLog?.Invoke($"成功解析帧: 头=0x{frameHeader:X2}, 长度={frameLength}");

                        // 从缓冲区移除已处理帧
                        _receiveBuffer.RemoveRange(0, frameLength);
                    }
                    else
                    {
                        // CRC校验失败，丢弃帧头并重试
                        OnError?.Invoke($"CRC校验失败: {BitConverter.ToString(candidateFrame)}");
                        _receiveBuffer.RemoveAt(0);
                    }
                }
            }
        }

        /// <summary>
        /// 验证Modbus CRC校验
        /// </summary>
        private bool ValidateModbusCrc(byte[] frame)
        {
            if (frame.Length < 4) return false;

            // 计算CRC的数据部分（排除最后2字节CRC）
            int dataLength = frame.Length - 2;
            ushort calculatedCrc = CalculateModbusCrc(frame, 0, dataLength);

            // 提取接收到的CRC（小端字节序：低字节在前）
            ushort receivedCrc = (ushort)(frame[frame.Length - 2] | (frame[frame.Length - 1] << 8));

            return calculatedCrc == receivedCrc;
        }

        /// <summary>
        /// 计算Modbus CRC校验码
        /// </summary>
        private ushort CalculateModbusCrc(byte[] data, int start, int length)
        {
            ushort crc = 0xFFFF;
            for (int i = start; i < start + length; i++)
            {
                crc ^= data[i];
                for (int j = 0; j < 8; j++)
                {
                    if ((crc & 0x0001) == 1)
                        crc = (ushort)((crc >> 1) ^ 0xA001);
                    else
                        crc = (ushort)(crc >> 1);
                }
            }
            return crc;
        }

        #endregion 数据解析逻辑

        #region 数据发送方法

        /// <summary>
        /// 发送数据到串口
        /// </summary>
        public void Send(byte[] data)
        {
            try
            {
                if (!_serialPort.IsOpen)
                    throw new InvalidOperationException("串口未打开");
                ushort crc = CalculateModbusCrc(data, 0, data.Length);
                byte[] send = data.Concat(BitConverter.GetBytes(crc)).ToArray();
                _serialPort.Write(send, 0, send.Length);
                OnLog?.Invoke($"发送数据: {ByteToString(send)}");
            }
            catch (Exception ex)
            {
                OnError?.Invoke($"发送错误: {ex.Message}");
                throw;
            }
        }

        /// <summary>
        /// 发送字符串数据到串口
        /// </summary>
        public void Send(string text)
        {
            byte[] data = System.Text.Encoding.ASCII.GetBytes(text);
            Send(data);
        }

        #endregion 数据发送方法

        #region 资源清理

        /// <summary>
        /// 关闭串口并释放资源
        /// </summary>
        public void Close()
        {
            _cts.Cancel();
            _serialPort.DataReceived -= DataReceivedHandler;

            if (_serialPort.IsOpen)
                _serialPort.Close();

            OnLog?.Invoke("串口已关闭");
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            Close();
            _cts.Dispose();
            _serialPort.Dispose();
        }

        #endregion 资源清理
    }
}